package top.lywivan.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/**
 * @desc
 * @author:ivan.liu
 */
public class NioServer {
    public static void main(String[] args) throws IOException {
        //打开一个ServerSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //设置非阻塞
        serverSocketChannel.configureBlocking(false);
        //绑定端口
        serverSocketChannel.socket().bind(new InetSocketAddress(8888));

        //打开一个Selector
        Selector selector = Selector.open();
        //将ServerSocketChannel注册到Selector
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        //启动一个线程执行多路复用
        new Thread(new SingleSelectorHandler(selector)).start();
    }

    static class SingleSelectorHandler implements Runnable{

        private final Selector selector;

        //装饰器模式
        public SingleSelectorHandler(Selector selector) {
            this.selector = selector;
        }

        @Override
        public void run() {
            //一直执行Selector的多路复用程序
            while (true){
                try {
                    //如果没有事件，则会阻塞等待
                    selector.select();
                    //没有阻塞，说明有事件发生
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()){
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        //处理当前事件
                        processSelectedKey(key);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //处理当前事件的逻辑
        private void processSelectedKey(SelectionKey key) throws IOException {
            //有效的key才处理
            if(key.isValid()){
                //不同的事件类型，处理方式不同
                if(key.isAcceptable()){
                    //发生了连接事件
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                    //获取客户端的连接
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    //设置非阻塞
                    socketChannel.configureBlocking(false);
                    //注册Selector，并注册读事件
                    socketChannel.register(selector,SelectionKey.OP_READ);
                }

                if(key.isReadable()){
                    //发生了读事件
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    //读取数据，放到buffer中
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    socketChannel.read(byteBuffer);
                    //切换读写模式
                    byteBuffer.flip();
                    //定义byte数组大小，大小为byteBuffer的数据大小
                    byte[] bytes=new byte[byteBuffer.remaining()];
                    //从byteBuffer中获取数据
                    byteBuffer.get(bytes);
                    String msg = new String(bytes, Charset.defaultCharset());
                    System.out.println(msg);
                    //执行业务操作。。。。

                    //准备byteBuffer的数据
                    byteBuffer.clear();
                    byteBuffer.put("hello client,iam nioserver".getBytes(StandardCharsets.UTF_8));
                    //转化读写模式
                    byteBuffer.flip();
                    //向客户端写出数据
                    socketChannel.write(byteBuffer);
                }
            }
        }
    }
}
